<?php

namespace app\socketio\controller;

require_once VENDOR_PATH . "workerman/phpsocket.io/src/autoload.php";

use PHPSocketIO\SocketIO;
use Workerman\Worker;
use Workerman\Lib\Timer;
use think\Db;

class Server
{
    // 全局数组保存uid在线数据
    private $uidConnectionMap = array();
    // 记录最后一次广播的在线用户数
    private $last_online_count = 0;
    // 记录最后一次广播的在线页面数
    private $last_online_page_count = 0;

    private  $sender_io ;
    // PHPSocketIO服务
    public function index(){

// PHPSocketIO服务
        $this->sender_io=new SocketIO(2120);
// 客户端发起连接事件时，设置连接socket的各种事件回调
        $this->sender_io->on('connection', function($socket){
            // 当客户端发来登录事件时触发
            $socket->on('login', function ($uid)use($socket){
                // 已经登录过了
                if(isset($socket->uid)){
                    return;
                }
                // 更新对应uid的在线数据

                $uid_data = json_decode($uid,true);
                $uid = (string)$uid;

                if(!empty($uid_data)){
                    $where['user_id']=$uid_data['user_id'];
                    $where['something_id']=$uid_data['something_id'];
                    $where['reply_user_id']=$uid_data['reply_user_id'];
                    $where['type']=$uid_data['type'];
                    $res=Db::name('chat')->where($where)->find();

//                    $db = new NewsDb();
//                    $res=$db->table('se_chat')
//                        ->where('user_id ='.$uid_data['user_id'].' and something_id='.$uid_data['something_id']
//                            .' and reply_user_id='.$uid_data['reply_user_id'])
//                        ->select();
                    if(!empty($res)){
                        $detailWhere['chat_id']=array('eq',$res['id']);
                        $detailWhere['user_id']=array('eq',$uid_data['id']);
                        $detailWhere['status']=array('eq',1);
                        $data=Db::name('chat_detail')
                            ->where($detailWhere)
                            ->select();
                    }else{
                        $data['user_id']=$uid_data['user_id'];
                        $data['reply_user_id']=$uid_data['reply_user_id'];
                        $data['something_id']=$uid_data['something_id'];
                        $data['type']=$uid_data['type'];
                        $data['createtime']=time();
                        Db::name('chat')->insert($data);
                    }
                    $socket->emit('new_msg_ok',json_encode($uid));
                }

                if(!isset($this->uidConnectionMap[$uid]))
                {
                    $this->uidConnectionMap[$uid] = 0;
                }
                // 这个uid有++$uidConnectionMap[$uid]个socket连接
                ++$this->uidConnectionMap[$uid];
                // 将这个连接加入到uid分组，方便针对uid推送数据
                $socket->join($uid);
                $socket->uid = $uid;

            });

            // 当客户端断开连接是触发（一般是关闭网页或者跳转刷新导致）
            $socket->on('disconnect', function () use($socket) {
                if(!isset($socket->uid))
                {
                    return;
                }
                global $uidConnectionMap, $sender_io;
                // 将uid的在线socket数减一
                if(--$this->uidConnectionMap[$socket->uid] <= 0)
                {
                    unset($this->uidConnectionMap[$socket->uid]);
                }
            });
        });

// 当$sender_io启动后监听一个http端口，通过这个端口可以给任意uid或者所有uid推送数据
        $this->sender_io->on('workerStart', function(){
            // 监听一个http端口
            $inner_http_worker = new Worker('http://0.0.0.0:2121');
            // 当http客户端发来数据时触发
            $inner_http_worker->onMessage = function($http_connection, $data){
                $_POST = $_POST ? $_POST : $_GET;
                // 推送数据的url格式 type=publish&to=uid&content=xxxx
                switch(@$_POST['type']){
                    case 'publish':
                        global $sender_io;
                        $to = @$_POST['to'];
                        $_POST['content'] = htmlspecialchars(@$_POST['content']);
                        $flightHandler = htmlspecialchars(@$_POST['callback']);

                        $uid_data = json_decode($to,true);


                        $whereChat['user_id']=$uid_data['user_id'];
                        $whereChat['something_id']=$uid_data['something_id'];
                        $whereChat['reply_user_id']=$uid_data['reply_user_id'];
                        $res=Db::name('chat')
                            ->where($whereChat)
                            ->find();
                        $time_=time();;

                        if($uid_data['id']==$res['user_id']){
                            $uidNew=$res['reply_user_id'];
                        }else{
                            $uidNew=$res['user_id'];
                        }

                        $data1['user_id']=$uidNew;
                        $data1['chat_id']=(int)$res['id'];
                        $data1['content']=$_POST['content'];
                        $data1['status']=1;
                        $data1['createtime']=$time_;

                        $youData=array();

                        $insertId=Db::name('chat_detail')->insertGetId($data1);

                        $youData['chat']['createtime']=$time_;
                        $youData['chat']['reply_user_id']=$uid_data['reply_user_id'];
                        $youData['chat']['user_id']=$uid_data['user_id'];
                        $youData['chat']['something_id']=$uid_data['something_id'];
                        $youData['chat_id']=(int)$res['id'];
                        $youData['content']= $data1['content'];
                        $youData['id']= $insertId;

                        $youData['time']= date("Y-m-d H:i:s",$time_) ;
                        $youData['id']= $insertId;


                        // 有指定uid则向uid所在socket组发送数据
                        if($to){

                            $youData['status']= 2;
                            $youData['type']='you';


                            Db::name('chat_detail')
                                ->where(['chat_id'=>array('eq',$res['id'])])
                                ->update(['status'=>2]);

                            $user=Db::name('user')
                                ->where(['id'=>$uidNew])
                                ->find();
                            $youData['avatar']=$user['avatar'];

                            $this->sender_io->to($to)->emit('new_msg',json_encode($youData));
                            // 否则向所有uid推送数据
                        }
                        // http接口返回，如果用户离线socket返回fail
                        if($to && !isset($this->uidConnectionMap[$to])){
                            $youData['status']= 1;
                            $youData['type']='i';
                            return $http_connection->send($flightHandler."('".json_encode($youData)."')");
                        }else{
                            $youData['status']= 1;
                            $youData['type']='i';
//                            if($uid_data['id']==$uid_data['user_id']){
//                                $uidNew=$uid_data['reply_user_id'];
//                            }else{
//                                $uidNew=$uid_data['id'];
//                            }

                            $user=Db::name('user')
                                ->where(['id'=>$uidNew])
                                ->find();
                            $youData['avatar']=$user['avatar'];
                            return $http_connection->send($flightHandler."('".json_encode($youData)."')");
                        }
                }
                return $http_connection->send('flightHandler("发送失败")');
            };
            // 执行监听
            $inner_http_worker->listen();

            // 一个定时器，定时向所有uid推送当前uid在线数及在线页面数
            Timer::add(1, function(){
                $this->sender_io->emit('update_online_count', json_encode($this->uidConnectionMap));
            });
        });

        if(!defined('GLOBAL_START'))
        {
            Worker::runAll();
        }
    }

}

